package cn.android.support.v7.lib.sin.crown.utils;

import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by 彭治铭 on 2018/3/18.
 */

public class ReflectionUtils {
    private static ReflectionUtils reflectionUtils;

    public static ReflectionUtils getInstance() {
        if (reflectionUtils == null) {
            reflectionUtils = new ReflectionUtils();
        }
        return reflectionUtils;
    }

    /**
     * 判断是否存在该方法
     *
     * @param methods    方法集合
     * @param methodName 方法名称
     * @return
     */
    public boolean checkMetMethod(Method[] methods, String methodName) {
        for (Method met : methods) {
            if (methodName.equals(met.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 利用反射，将所有属性都赋值为空,该属性必须具备Set()方法。原理就是利用反射set方法赋值为空的。这里没有用到get()方法。对get()方法没有要求。
     * <p>
     * 不管是在子类中调用，还是在父类中调用，获取的都是子类的属性。无法获取父类的属性。只能获取当前的子类属性。
     *
     * @param object this
     * @param clazz  this.getClass()
     */
    public void fieldToNull(Object object, Class clazz) {
        //释放对Activity的引用。防止内存泄漏。
        Field[] fields = clazz.getDeclaredFields();//拿到数据成员【得到的是当前类的属性，不是父类。对父类无效,哪怕是在父类中调用，获取的也是子类的属性。】
        Method[] methods = clazz.getDeclaredMethods();//拿到所有的方法。
        for (Field f : fields) {
            //Log.e("test", "所有成员变量:\t" + f.getName());
            try {
                String name = f.getName();
                if (name.equals("$change") || name.equals("serialVersionUID")) {
                    continue;
                }
                String methodName = "set" + name.replaceFirst(name.substring(0, 1),
                        name.substring(0, 1).toUpperCase());//set方法后面第一个首字母大写，这个一定要注意。检测一下自己的set后面第一个字母是否大写。
                if (!checkMetMethod(methods, methodName)) {
                    continue;//该方法不存在
                }
                f.setAccessible(true);//设置该属性，可访问
                Class type = f.getType();
                //Log.e("test", "类型:\t" + type);
                if (chekBaseType(type.toString())) {
                    continue;//不能赋值为null
                }
                //获取属性的set方法【如果该set方法不存在，就会报错】
                Method method = clazz.getMethod(methodName, type);
                //将值设为null
                method.invoke(object, new Object[]{null});
            } catch (Exception e) {
                Log.e("test", "反射赋空值异常:\t" + e.getMessage());
            }
        }
        //局部变量，方法执行完成，变量会自动释放掉，可以不需要手动赋值为空。
        object = null;
        clazz = null;
    }

    /**
     * 判断是否为基本类型，true 就不能赋值null,false可以赋值null
     *
     * @param type
     * @return
     */
    public boolean chekBaseType(String type) {
        if (type.equals("class java.lang.Double")) {
            return true;
        } else if (type.equals("class java.lang.Float")) {
            return true;
        } else if (type.equals("class java.lang.Integer")) {
            return true;
        } else if (type.equals("class java.lang.Boolean")) {
            return true;
        } else if (type.equals("class java.lang.Long")) {
            return true;
        } else if (type.equals("long") || type.equals("int") || type.equals("float") || type.equals("double") || type.equals("boolean")) {
            return true;
        } else {
            return false;
        }
    }

}
